package neo.aoi;

import java.util.HashSet;
import java.util.Set;

import artofillusion.math.Vec3;

/**
 * This class represents a set of Vec3 objects. An instance of this class is for
 * the most part a <code>HashSet&lt;Vec3&gt;</code> object. This class was
 * implemented as a result that an ordinary <code>HashSet</code> can not
 * detect if two <code>Vec3</code> objects are equal. The similarity of two
 * <code>Vec3</code> objects is checked after rounding, using a
 * <code>RoundUtils</code> object, with the specified precision. If no
 * precision is specified, the default value is used.
 * 
 * @see RoundUtils
 * 
 * @author Carlos Martinez
 */
public class Vec3Set extends HashSet<Vec3> {
	private static final long serialVersionUID = -7228361017137043928L;

	private RoundUtils _rounder;

	/**
	 * Creates a <code>Vec3Set</code> with default rounding precision.
	 * 
	 */
	public Vec3Set() {
		_rounder = new RoundUtils();
	}

	/**
	 * Creates a <code>Vec3Set</code> object which uses the given round_places
	 * precision for rounding.
	 * 
	 * @param round_places
	 *            Number of places after decimal point used for rounding
	 * @see RoundUtils#setRoundingPlaces(int)
	 */
	public Vec3Set(int round_places) {
		_rounder = new RoundUtils();
		_rounder.setRoundingPlaces(round_places);
	}

	/**
	 * Creates a <code>Vec3Set</code> object which with rounding precision
	 * matching the given resolution.
	 * 
	 * @param resolution
	 *            Rounding resolution
	 * @see RoundUtils#matchRoundingPlaces(double)
	 */
	public Vec3Set(double resolution) {
		_rounder = new RoundUtils();
		_rounder.matchRoundingPlaces(resolution);
	}

	/**
	 * As defined by <code>Set</code> interface.
	 * 
	 * @param o
	 *            Object to be added
	 * @return As defined by <code>Set</code> interface.
	 * @see Set
	 */
	public boolean add(Vec3 o) {
		if (contains(o))
			return false;
		return super.add(new Vec3(_rounder.round(o.x), _rounder.round(o.y),
				_rounder.round(o.z)));
	}

	/**
	 * As defined by <code>Set</code> interface. Additional checking is
	 * performed for <code>Vec3</code> objects; the set is checked to insure
	 * that there is no element e such that round(e) equals round(o)
	 * 
	 * @param o
	 *            element whose presence in this set is to be tested.
	 * @return As defined by <code>Set</code> interface.
	 * @see Set
	 */
	public boolean contains(Object o) {
		if (o instanceof Vec3) {
			Vec3 obj = (Vec3) o;
			double rx = _rounder.round(obj.x);
			double ry = _rounder.round(obj.y);
			double rz = _rounder.round(obj.z);
			for (Vec3 v : this)
				if (rx == v.x && ry == v.y && rz == v.z)
					return true;
		}
		return false;
	}
}
